package ftl.games.piratas;
/*
 * This program is supposed to record the users touch input on screen and with that, move the sprite on screen
 * along an A* path. 
 * Some Useful resources
 * http://www.andengine.org/forums/development/tmx-and-touch-t1682.html
 * http://www.andengine.org/forums/updates/new-pathfinding-t1227.html
 * http://www.andengine.org/forums/tutorials/tmxtiledmapexample-w-a-pathing-t1982.html
 * http://www.andengine.org/forums/updates/new-pathfinding-t1227-20.html
 * http://www.andengine.org/forums/post14069.html#p14069
 * http://www.andengine.org/forums/post14421.html#p14421
 * 
 */
import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.BoundCamera;
import org.anddev.andengine.engine.handler.IUpdateHandler;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.IEntity;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLayer;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLoader;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXProperties;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXProperty;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTile;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTileProperty;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTiledMap;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLoader.ITMXTilePropertiesListener;
import org.anddev.andengine.entity.modifier.IEntityModifier;
import org.anddev.andengine.entity.modifier.IEntityModifier.IEntityModifierListener;
import org.anddev.andengine.entity.modifier.PathModifier;
import org.anddev.andengine.entity.modifier.PathModifier.IPathModifierListener;
import org.anddev.andengine.entity.modifier.PathModifier.Path;
import org.anddev.andengine.entity.primitive.Rectangle;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.anddev.andengine.entity.sprite.AnimatedSprite;
import org.anddev.andengine.entity.util.FPSLogger;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.opengl.texture.Texture;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
import org.anddev.andengine.ui.activity.BaseGameActivity;
import org.anddev.andengine.util.constants.Constants;
import org.anddev.andengine.util.modifier.IModifier;
import org.anddev.andengine.util.path.ITiledMap;
import org.anddev.andengine.util.path.astar.AStarPathFinder;
import org.anddev.andengine.util.path.astar.EuclideanHeuristic;

import android.util.Printer;
import android.widget.Toast;
 
public class test extends BaseGameActivity implements IOnSceneTouchListener {
 
        // ===========================================================
        // Constants
        // ===========================================================
 
        private static final int CAMERA_WIDTH = 480;  //15
        private static final int CAMERA_HEIGHT = 320; 
        private static final int TILE_WIDTH = 32;
        //Controls the speed the sprite will move at. Lower is faster
		private static final float mSpeed = (float) 0.3;
 
        // ===========================================================
        // Fields
        // ===========================================================
 
        private BoundCamera mBoundChaseCamera;
        private BitmapTextureAtlas mTexture;
        private TiledTextureRegion mPlayerTextureRegion;
        private TMXTiledMap mTMXTiledMap;
        private TMXLayer tmxLayer;
        private TMXTile tmxTile;
        private  AnimatedSprite player;
        private org.anddev.andengine.util.path.Path A_path;
        private AStarPathFinder<TMXLayer> finder;
        private float[] playerFootCordinates;
        private Path mCurrentPath;      
		private boolean isWalking;
		private int mWaypointIndex;
		private PathModifier mMoveModifier;
		private IEntityModifier mPathTemp;
		private String test;
    	private int cCounter = 0;
 
        // ===========================================================
        // Constructors
        // ===========================================================
 
        // ===========================================================
        // Getter & Setter
        // ===========================================================
 
        // ===========================================================
        // Methods for/from SuperClass/Interfaces
        // ===========================================================
 
        @Override
        public Engine onLoadEngine() {
        	//Initializes the Engine and sets the height and width
            this.mBoundChaseCamera = new BoundCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
            //Sets the orientation of the screen along with the resolution(Multiple displays will see the same image)
            final EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE, new RatioResolutionPolicy(CAMERA_WIDTH , CAMERA_HEIGHT), this.mBoundChaseCamera);
        	//Sets the touch interactions to get processed during the update thread??
        	engineOptions.getTouchOptions().setRunOnUpdateThread(true); 
        	//Initializes the Engine
        	Engine engine = new Engine(engineOptions);
        	//Returns the Engine
        	return engine;
        }
        
        /*
         * (non-Javadoc)
         * @see org.anddev.andengine.ui.IGameInterface#onLoadResources()
         * loads the reasources
         */
        @Override
        public void onLoadResources() {
        	this.mTexture = new BitmapTextureAtlas(128, 128, TextureOptions.DEFAULT);
                
        	this.mPlayerTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mTexture, this, "gfx/car.png", 0, 0, 2, 1); // 72x128
 
        	this.mEngine.getTextureManager().loadTexture(this.mTexture);
        }
 
        @Override
        public Scene onLoadScene() {
        	        	
        	this.mEngine.registerUpdateHandler(new FPSLogger());
 
        	final Scene scene = new Scene();


        	try {
                final TMXLoader tmxLoader = new TMXLoader(this, this.mEngine.getTextureManager(),
                		TextureOptions.BILINEAR_PREMULTIPLYALPHA,new ITMXTilePropertiesListener() {
	                @Override
	                public void onTMXTileWithPropertiesCreated(final TMXTiledMap pTMXTiledMap,
	                		final TMXLayer pTMXLayer, final TMXTile pTMXTile, final TMXProperties<TMXTileProperty> pTMXTileProperties) {
	                		if(pTMXTileProperties.containsTMXProperty("Collide", "true")) {
                            	//I tried to put the Tile ids in an array here but the program kept hanging	                            
	                        }
	                }
                });
                this.mTMXTiledMap = tmxLoader.loadFromAsset(this, "tmx/desert_astar.tmx");
                Toast.makeText(this, "Collide count in this TMXTiledMap: " + this.cCounter, Toast.LENGTH_LONG).show();
             // These must be defined for the findpath() method to work
                final ITiledMap<TMXLayer> tmap = new ITiledMap<TMXLayer>()
                {
                	 

					// Pretty self explanatory
                    @Override
                    public int getTileColumns() {
                            return mTMXTiledMap.getTileColumns();
                    }
                   
                    // Pretty self explanatory
                    @Override
                    public int getTileRows()
                    {
                            return mTMXTiledMap.getTileRows();
                    }
                   
                    // Lets you customize what blocks you want to be considered blocked
                    @Override
                    public boolean isTileBlocked(TMXLayer pTile, final int pToTileColumn, final int pToTileRow)
                    {   
                    	//This is the array of all the tiles that can be collided with
                    	//I added them manually. It makes it easier if you've organized your tile maps
                    	//since you wouldn't need the for loop
                    	final int[] CollideTiles = {31,32,47};
                    	TMXTile block = tmxLayer.getTMXTile(pToTileColumn, pToTileRow);
                    	for(int tempCollide : CollideTiles){
	                    	if(block.getGlobalTileID() == tempCollide){
	                    		return true;
	                    	}
                    	}
                        // Return false by default = no tiles blocked
                        return false;
                    }
                   
                    // This is the key function to understand for AStar pathing
                    // Returns the cost of the next tile in the path
                    @Override
                    public float getStepCost(final TMXLayer pTile, final int pFromTileColumn, final int pFromTileRow, final int pToTileColumn, final int pToTileRow)
                    {		
                    	//I coded this it because it caused more problems than it was worth, but this is where the path value is decided
                    		/*
                            //grab the first property from a tile at pToTileColumn x pToTileRow
                            TMXProperty cost = tmxLayer.getTMXTile(pToTileColumn, pToTileRow).getTMXTileProperties(mTMXTiledMap).get(0);
                            //Gets the value of the string
                            return Float.parseFloat(cost.getValue());*/
                    	return 0;
                           
                    }
                   
                    // If the tile is processed by findpath(), any extra code you might want goes here
                    @Override
                    public void onTileVisitedByPathFinder(int pTileColumn, int pTileRow) {
                            // Do Nothing
                    }
                };
                // Add the non-object layers to the scene
                tmxLayer = this.mTMXTiledMap.getTMXLayers().get(0);
                scene.attachChild(tmxLayer);

 
                /* Make the camera not exceed the bounds of the TMXEntity. */
                this.mBoundChaseCamera.setBounds(0, tmxLayer.getWidth(), 0, tmxLayer.getHeight());
                this.mBoundChaseCamera.setBoundsEnabled(true);
 
                /* Calculate the coordinates for the face, so its centered on the camera. */
                final int centerX = (CAMERA_WIDTH - this.mPlayerTextureRegion.getTileWidth()) / 2+10;
                final int centerY = (CAMERA_HEIGHT - this.mPlayerTextureRegion.getTileHeight()) / 2+10;

                // Declare the AStarPathFinder
                // First Param: above ITiledMap
                // Second Param: Max Search Depth - Care, if this is too small your program will crash
                // Third Param: allow diagonal movement or not
                // Fourth Param: Heuristics you want to use in the A* algorithm (optional)
                finder = new AStarPathFinder<TMXLayer>(tmap, 15, false);
                
                // Declare Animated sprite 
                // First Param: defines the x pixel position the sprite will be created at
                // Second Param: defines the y pixel position the sprite will be created at
                // Third Param: Sets the texture to be used 
                player = new AnimatedSprite(centerX, centerY, this.mPlayerTextureRegion);
                        
                //Sets the camera to focus on the player enitity
                this.mBoundChaseCamera.setChaseEntity(player);
 
                /* Now we are going to create a rectangle that will  always highlight the tile below the feet of the pEntity. */
                final Rectangle currentTileRectangle = new Rectangle(0, 0, this.mTMXTiledMap.getTileWidth(), this.mTMXTiledMap.getTileHeight());
                currentTileRectangle.setColor(1, 0, 0, 0.25f);
                scene.getLastChild().attachChild(currentTileRectangle);

                scene.registerUpdateHandler(new IUpdateHandler() {
	                @Override
	                public void reset() { }
	
	                @Override
	                public void onUpdate(final float pSecondsElapsed) {
	                	/* Get the scene-coordinates of the tile center.*/
	                	playerFootCordinates = player.convertLocalToSceneCoordinates(16, 16);
	
	                    /* Get the tile where the center of the current tile is. */
	                    tmxTile = tmxLayer.getTMXTileAt(playerFootCordinates[Constants.VERTEX_INDEX_X],
	                    	playerFootCordinates[Constants.VERTEX_INDEX_Y]);
	                    if(tmxTile != null) {
	                        // tmxTile.setTextureRegion(null); <-- Rubber-style removing of tiles =D
	                        currentTileRectangle.setPosition(tmxTile.getTileX(), tmxTile.getTileY());
	                    }
	                }
                });
                //Add player sprite to the scene
                scene.getLastChild().attachChild(player);
                //Allows the scene to be touched
                scene.setOnSceneTouchListener(this);
 
        	}catch (Exception e) {
        	}
 
        	return scene;
        }
 
        @Override
        public void onLoadComplete() {
 
        }
 
        @Override
        public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent){
        	//if the user touches the screen then...
        	if(pSceneTouchEvent.isActionDown()){
        		//Calls the Walk to method, which has two parameters
        		//First & Second Param: are the touched x and y position 
        		//Third Param: is the scene
        		walkTo(pSceneTouchEvent.getX(), pSceneTouchEvent.getY(), pScene);        	                    
                        
        	}
        	return true;
        }
 
        // ===========================================================
        // Methods
        // ===========================================================
        
        //This method controls the path the sprite will take once a location is passed into it
        public void walkTo(final float pX, final float pY, Scene pScene){
        	
            //Puts the touch events into an array
            final float[] pToTiles = pScene.convertLocalToSceneCoordinates(pX, pY);
         
            //Gets the tile at the touched location
            final TMXTile tmxTilePlayerTo =  tmxLayer.getTMXTileAt(
                   pToTiles[Constants.VERTEX_INDEX_X],
                   pToTiles[Constants.VERTEX_INDEX_Y]
            );
                           
        /*********/ //if is walking and there is a A_path ******************
            if (isWalking == true && A_path != null) {
            	//Calls the Walk to next waypoint method,
        		//First & Second Param: are the touched x and y position 
        		//Third Param: is the scene
                walkToNextWayPoint(pX,pY,pScene);
            }
                       
            else if (A_path == null ) {                
                // Create the path with findPath()
                // First Param: TMXLayer in this case, templated through the above ITiledMap and AStarPathFinder functions
                // Second Param: Max Cost of a complete path, NOT A SINGLE TILE! - if value is too low your program will crash
                // Third & Fourth Param: From Column and From Row - Starting tile location
                // Fifth & Sixth Param: To Column and To Row - Ending tile location            	
                A_path = finder.findPath(tmxLayer,100,
                     //Sprite's initial tile location
                     tmxTile.getTileColumn(),
                     tmxTile.getTileRow(),
                     //Sprite's final tile location
                     tmxTilePlayerTo.getTileColumn(),
                     tmxTilePlayerTo.getTileRow());
         
                //Calls the Load path method
                loadPathFound();
            }
        }
        //If the sprite is moving and the screen is touched then this method will be called.
        //It creates a sub path that creates a smooth transition to the center of a tile before rerouting
        private void walkToNextWayPoint(final float pX, final float pY, final Scene pScene) {
        	//Unregisters the current paths
            player.unregisterEntityModifier(mMoveModifier);
            player.unregisterEntityModifier(mPathTemp); //mPathTemp is another global PathModifier
            
            //Creates a copy of the path currently being walked
            final Path lPath = mCurrentPath.clone();
            
            //create a new path with length 2 from current sprite position to next original path waypoint
            final Path path = new Path(2);
            //Continues the path for one more tile 
            path
                .to(player.getX(), player.getY())
                .to(lPath.getCoordinatesX()[mWaypointIndex+1], lPath.getCoordinatesY()[mWaypointIndex+1]);
            
            //recalculate the speed. TILE_WIDTH is the tmx tile width, use yours
            float lSpeed = path.getLength() * mSpeed / (TILE_WIDTH); 
                       
            //Create the modifier of this subpath
            mPathTemp = new PathModifier(lSpeed, path, new IEntityModifierListener() {
                               
                public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
                                       
                }
                               
                public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
                               
                }
            }, new IPathModifierListener() {
                               
                public void onPathWaypointStarted(final PathModifier pPathModifier, final IEntity pEntity,  int pWaypointIndex) {
                	                   
            }
                
                public void onPathWaypointFinished(PathModifier pPathModifier, IEntity pEntity,
                    int pWaypointIndex) {
                                       
                }
                               
                public void onPathStarted(PathModifier pPathModifier, IEntity pEntity) {
         
                }
                               
                public void onPathFinished(PathModifier pPathModifier, IEntity pEntity) {
                		//Once the subpath is finished the a new one is created at the new touched location
                        A_path = null;
                        walkTo(pX, pY,pScene);
                        //Stops the animation of the player once it stops
                        player.stopAnimation();
                }
            });
            //Registers the newly created path modifier           
            player.registerEntityModifier(mPathTemp);          
        }
        
        //Creates the A* Path and executes it
        private void loadPathFound() {
        	   
            if (A_path != null) {
                //Global var
                mCurrentPath = new Path(A_path.getLength());
                int tilewidth = mTMXTiledMap.getTileWidth();
                int tileheight = mTMXTiledMap.getTileHeight();
                                       
                for(int i = 0; i < A_path.getLength(); i++){
                    mCurrentPath.to(A_path.getTileColumn(i) * tilewidth, A_path.getTileRow(i) * tileheight);
                }
                doPath();
            }
        }
        //Creates the modifier for the A*Path
        private void doPath() {
        	 
            //Create this mMoveModifier as Global, there is mSpeed  too -> player speed
            mMoveModifier = new PathModifier(mSpeed * A_path.getLength(), mCurrentPath, new IEntityModifierListener() {
         
                public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
         
                }
               
                public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
         
                }
            }, new PathModifier.IPathModifierListener() {


				public void onPathWaypointStarted(final PathModifier pPathModifier, final IEntity pEntity,  int pWaypointIndex) {
					 
                    //Character animation are controlled here
                    switch(A_path.getDirectionToNextStep(pWaypointIndex)) {
                    case DOWN:
                            //player.animate(new long[]{200, 200, 200}, 6, 8, true);
                            break;
                    case RIGHT :
                            //player.animate(new long[]{200, 200, 200}, 3, 5, true);
                            break;
                    case UP:
                            //player.animate(new long[]{200, 200, 200}, 0, 2, true);
                            break;
                    case LEFT:
                            //player.animate(new long[]{200, 200, 200}, 9, 11, true);
                            break;
                    default:
                            break;
                    }            
                               
                    //Keep the waypointIndex in a Global Var
                    mWaypointIndex = pWaypointIndex;
               
                }
                               
                public void onPathWaypointFinished(PathModifier pPathModifier, IEntity pEntity,
                        int pWaypointIndex) {
               
                }
                                       
                public void onPathStarted(PathModifier pPathModifier, IEntity pEntity) {
         
                    //Set a global var
                    isWalking = true;
                }
                                       
                public void onPathFinished(PathModifier pPathModifier, IEntity pEntity) {
         
                    //Stop walking and set A_path to null
                    isWalking = false;
                    A_path = null;
                    player.stopAnimation();
                }
         
            });
         
            player.registerEntityModifier(mMoveModifier);
        }

        
 
        // ===========================================================
        // Inner and Anonymous Classes
        // ===========================================================
 
}